import React, { useMemo, useState } from 'react';
import { useDrag, useDrop } from 'react-dnd';
import { FolderOutlined, FileOutlined, CaretDownOutlined, CaretRightOutlined } from '@ant-design/icons';
import { useSelector, useDispatch } from 'react-redux'
import { Modal, Input, Dropdown } from 'antd';
import { State } from '@/apps/panel/reducers'
import type { EntryNode } from '@/apps/panel/reducers'
import * as act from '@/apps/panel/actions'
import { APP_STATUS } from '@/common/constant'
import { treeMap, treeFilter } from '@/common/ts_utils';
import { Without } from '@/common/types';
import { MacroResultStatus } from '@/types/macro_extra_data'
import './FolderMenu.less';
import { Dispatch } from 'redux';

enum FileNodeType {
    File = 'file',
    Folder = 'folder'
}

interface FolderNodeProps {
    item: any;
    level: number;
    onMove: (sourceId: string, targetId: string, isDirectory: boolean) => void;
    onClick: (item: string) => void;
    macroCreateFolder: any;
    macroCreateFile: any;
}

function FolderNode({ item, level, onMove, onClick, macroCreateFolder, macroCreateFile }: FolderNodeProps) {
    const dispatch = useDispatch();
    const [isExpanded, setIsExpanded] = useState(true);

    const [{ isDragging }, drag] = useDrag({
        type: 'FOLDER_ITEM',
        item: { id: item.id, type: item.type },
        collect: (monitor) => ({
            isDragging: monitor.isDragging(),
        }),
    });

    const [{ isOver }, drop] = useDrop({
        accept: 'FOLDER_ITEM',
        drop: (draggedItem: { id: string; type: string }) => {
            onMove(draggedItem.id, item.id, draggedItem.type === 'folder');
        },
        collect: (monitor) => ({
            isOver: monitor.isOver(),
        }),
    });

    return (
        <div
            ref={(node) => {
                drag(drop(node));
            }}
            className={`folder-node ${isDragging ? 'dragging' : ''} ${isOver ? 'drop-target' : ''}`}
        >
            <Dropdown menu={{
                items: item.type === 'folder' ? [
                    {
                        key: 'newFile',
                        label: '新建用例...',
                    },
                    {
                        key: 'newFolder',
                        label: '新建文件夹...',
                    },
                    {
                        key: 'renameFolder',
                        label: '重命名...',
                    },
                    {
                        key: 'deleteFolder',
                        label: '删除',
                    },
                    {
                        type: 'divider',
                    },
                    {
                        key: 'playFolder',
                        label: '运行全部',
                    },
                    {
                        key: 'loopPlayFolder',
                        label: '循环运行',
                    },
                    {
                        type: 'divider',
                    },
                    {
                        key: 'import',
                        label: '导入JSON或ZIP',
                    },
                ] : [
                    {
                        key: 'rename',
                        label: '重命名...',
                    },
                    {
                        key: 'duplicate',
                        label: '复制...',
                    },
                    {
                        key: 'delete',
                        label: '删除',
                    },
                    {
                        type: 'divider',
                    },
                    {
                        key: 'play',
                        label: '运行',
                    },
                    {
                        key: 'playFromHere',
                        label: '从此用例开始运行',
                    },
                    {
                        type: 'divider',
                    },
                    {
                        key: 'exportJson',
                        label: '导出为JSON',
                    },
                    {
                        key: 'exportZip',
                        label: '导出为zip',
                    },
                    {
                        key: 'addBookmarks',
                        label: '加入书签',
                    },
                ],
                onClick: (e) => {
                    switch (e.key) {
                        case 'newFile': {
                            macroCreateFile({
                                dir: item.entryPath
                            })
                            break
                        }
                        case 'newFolder': {
                            macroCreateFolder({
                                dir: item.entryPath
                            })
                            break
                        }
                        case 'renameFolder': {
                            let newName = item.name
                            Modal.confirm({
                                title: '文件夹重命名',
                                content: <Input
                                    defaultValue={newName}
                                    onChange={(e) => {
                                        newName = e.target.value
                                    }}
                                />,
                                onOk: () => {
                                    dispatch(act.macroRenameFolder({
                                        dir: item.entryPath,
                                        newName
                                    }) as any)
                                }
                            })
                            break
                        }
                        case 'deleteFolder': {
                            Modal.confirm({
                                title: '删除文件夹',
                                content: '删除后数据无法恢复，确认删除吗？',
                                onOk: () => {
                                    dispatch(act.macroDeleteFolder({ dir: item.entryPath }) as any)
                                }
                            })
                            break
                        }
                        case 'delete': {
                            Modal.confirm({
                                title: '删除用例',
                                content: '删除后数据无法恢复，确认删除吗？',
                                onOk: () => {
                                    dispatch(act.removeTestCase(item.id) as any)
                                }
                            })
                            break
                        }
                        case 'rename': {
                            let newName = item.name
                            Modal.confirm({
                                title: '用例重命名',
                                content: <Input
                                    defaultValue={newName}
                                    onChange={(e) => {
                                        newName = e.target.value
                                    }}
                                />,
                                onOk: () => {
                                    dispatch(act.renameTestCase(newName, item.id) as any)
                                }
                            })
                            break
                        }
                    }
                },
            }}
                trigger={['contextMenu']}
            >
                <div className="folder-content">
                    {item.type === 'folder' && (
                        <span
                            className="expand-icon"
                            onClick={() => setIsExpanded(!isExpanded)}
                        >
                            {isExpanded ? <CaretDownOutlined /> : <CaretRightOutlined />}
                        </span>
                    )}
                    {item.type === 'folder' ? <FolderOutlined /> : <FileOutlined />}
                    <span className="item-name" onClick={() => onClick(item.id)}>{item.name}</span>
                </div>
            </Dropdown>

            {isExpanded && item.children && (
                <div className="folder-children" style={{ paddingLeft: `${level * 20}px` }} >
                    {item.children.map((child: any) => (
                        <FolderNode
                            key={child.id}
                            item={child}
                            level={level + 1}
                            onMove={onMove}
                            onClick={onClick}
                            macroCreateFolder={macroCreateFolder}
                            macroCreateFile={macroCreateFile}
                        />
                    ))}
                </div>
            )}
        </div>
    );
};

export default function FolderMenu({ macroCreateFolder, macroCreateFile }: any) {

    const dispatch = useDispatch<Dispatch<any>>()
    const status = useSelector((state: State) => state.status)
    const editing = useSelector((state: State) => state.editor.editing)
    const macroFolderStructure = useSelector((state: State) => state.editor.macroFolderStructure)
    const macrosExtra = useSelector((state: State) => state.editor.macrosExtra)
    const macroId = useSelector((state: State) => state.editor.editing.meta.src?.id) || '__untitled__';
    const focusArea = useSelector((state: State) => state.ui.focusArea)
    const searchText = useSelector((state: State) => state.macroQuery)
    const sidebarFocused = focusArea === 'sidebar'

    // 转化为目录数据
    const filteredMacroFileNodeData = useMemo<any[]>(() => {

        const getClassName = (data: Without<any, 'children'>): string => {
            const klasses: string[] = []
            const id = data.fullPath
            const status = macrosExtra[id] && macrosExtra[id].status

            klasses.push(
                (() => {
                    switch (status) {
                        case MacroResultStatus.SUCCESS:
                            return 'success'

                        case MacroResultStatus.ERROR:
                            return 'error'

                        case MacroResultStatus.ERROR_IN_SUB:
                            return 'error-in-sub'

                        default:
                            return 'normal'
                    }
                })()
            )

            if (macroId === id) {
                klasses.push('selected')
            }

            if (!sidebarFocused) {
                klasses.push('blur')
            }

            return klasses.join(' ')
        }

        const getFolded = (data: Without<any, 'children'>): boolean => {
            const id = data.fullPath
            const folded = macrosExtra[id] && macrosExtra[id].folded || false

            return folded
        }

        const entryNodeToFileNodeData = (entryNode: any) => {
            return treeMap((entryData: Without<any, 'children'>, paths: number[]): Without<any, 'children'> => {
                return {
                    id: entryData.fullPath,
                    type: entryData.isFile ? FileNodeType.File : FileNodeType.Folder,
                    level: paths.length,
                    selected: false,
                    name: entryData.name,
                    entryPath: entryData.fullPath,
                    folded: getFolded(entryData),
                    className: getClassName(entryData)
                }
            }, entryNode)
        }

        const macroFileNodeData = macroFolderStructure.map((node) => entryNodeToFileNodeData(node))

        const trimSearchText = searchText?.trim().toLowerCase() || ''
        if (trimSearchText.length === 0) {
            return macroFileNodeData
        }

        return macroFileNodeData.map((node) => {
            const filteredNode = treeFilter((data) => data.name.toLowerCase().indexOf(trimSearchText) !== -1, node)

            if (!filteredNode) {
                return null
            }

            return treeMap((data) => ({
                ...data,
                folded: false
            }),
                filteredNode
            )
        }).filter(Boolean)

    }, [macroFolderStructure, macrosExtra, macroId, sidebarFocused, searchText])

    const findItem = (items: any[], id: string): EntryNode | null => {
        for (const item of items) {
            if (item.id === id) return item;
            if (item.children) {
                const found = findItem(item.children, id);
                if (found) return found;
            }
        }
        return null;
    };

    const removeItem = (items: any[], id: string): EntryNode[] => {
        return items.filter((item) => {
            if (item.id === id) return false;
            if (item.children) {
                item.children = removeItem(item.children, id);
            }
            return true;
        });
    };

    const addItem = (items: any[], targetId: string, itemToAdd: EntryNode): EntryNode[] => {
        return items.map((item) => {
            if (item.id === targetId) {
                return {
                    ...item,
                    children: [...(item.children || []), itemToAdd],
                };
            }
            if (item.children) {
                return {
                    ...item,
                    children: addItem(item.children, targetId, itemToAdd),
                };
            }
            return item;
        });
    };

    // 
    const handleMove = (sourceId: string, targetId: string, isDirectory: boolean) => {
        dispatch(act.macroMoveEntry({
            entryId: sourceId,
            dirId: targetId,
            isSourceDirectory: isDirectory
        }))
    };

    // 选择用例
    const changeTestCase = (id: string) => {

        if (status !== APP_STATUS.NORMAL) return
        if (editing.meta.src && editing.meta.src.id === id) return
        // Do not ask for save if it's currently on Untitled and no commands in it
        if (editing.commands.length === 0 && !editing.meta.src) {
            dispatch(act.editTestCase(id) as any)
        } else {
            // return getSaveTestCase().saveOrNot().then(go)
            dispatch(act.editTestCase(id) as any)
        }
    }

    return (
        <div className="folder-menu">
            {filteredMacroFileNodeData.map((item) => (
                <FolderNode
                    key={item.id}
                    item={item}
                    level={0}
                    onMove={handleMove}
                    onClick={changeTestCase}
                    macroCreateFolder={macroCreateFolder}
                    macroCreateFile={macroCreateFile}
                />
            ))}
        </div>
    );
};

